package com.gengzp.rpc.core.impl;

import com.gengzp.rpc.core.RpcInvocationCoreFunc;
import com.gengzp.rpc.core.RpcProducerCoreFunc;
import com.gengzp.rpc.core.RpcRequestIdentificationCoreFunc;
import com.gengzp.rpc.exception.RpcException;
import com.gengzp.rpc.model.common.req.RpcRequest;
import com.gengzp.rpc.model.common.resp.RpcResponse;
import com.gengzp.rpc.model.remoteTransaction.req.RpcRollbackRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import static com.gengzp.rpc.constants.RpcBeanNameConstants.RPC_REMOTE_TRANSACTION_ROLLBACK_SUFFIX;

/**
 * @ClassName RpcProducerCoreFuncImpl
 * @Description rpc远程调用生产者端核心方法实现类
 * @Author gengzp
 * @Date 2025/8/23 18:02
 */
@Component
public class RpcProducerCoreFuncImpl implements RpcProducerCoreFunc {

    private static final Logger logger = LoggerFactory.getLogger(RpcProducerCoreFuncImpl.class);

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private RpcInvocationCoreFunc rpcInvocationCoreFunc;

    @Autowired
    private RpcRequestIdentificationCoreFunc rpcRequestIdentificationCoreFunc;

    @Override
    public RpcResponse<?> doExecuteRemoteCallProducer(RpcRequest req) throws RpcException {
        try {
            // 1.首先将当前远程调用的远程事务启用状态保存到线程变量
            rpcRequestIdentificationCoreFunc.saveEnableRemoteTransactionFlag(req.getEnableRemoteTransactionFlag());

            // 2.根据接口的类型获取实现类
            Object bean = null;
            try {
                bean = applicationContext.getBean(req.getInterfaceClass());
            } catch (Exception ignored) {
            }
            if (bean == null) {
                throw RpcException.get(String.format("获取远程调用接口 %s 的实现类失败, 请检查是否正确配置",
                        req.getInterfaceClass().getSimpleName()));
            }

            // 3.获取要调用的方法
            Method method = null;
            try {
                method = bean.getClass().getMethod(req.getMethodName(), req.getParameterTypes());
            } catch (Exception ignored) {
            }
            if (method == null) {
                throw RpcException.get(String.format("获取远程调用接口 %s 的方法 %s 失败, 请检查是否正确配置",
                        req.getInterfaceClass().getSimpleName(), req.getMethodName()));
            }
            method.setAccessible(true);

            // 4.通过反射调用指定方法
            Object invoke = method.invoke(bean,
                    // 4.1 转换参数列表类型 (将 Object 转换为具体的类型才能进行反射调用)
                    rpcInvocationCoreFunc.convertArgsToSpecificType(req.getArgs(), req.getParameterTypes()));

            // 5.组装远程事务标识
            Boolean enableRemoteTransactionFlag = rpcRequestIdentificationCoreFunc
                    .getCurrentRequestIdentification().getEnableRemoteTransactionFlag();

            // 6.组装远程调用http请求返回对象
            return RpcResponse.success(invoke, enableRemoteTransactionFlag);
        } catch (InvocationTargetException e) {
            throw RpcException.get(e.getTargetException().getMessage());
        } catch (Exception e) {
            throw RpcException.get(e.getMessage());
        }
    }

    @Override
    public RpcResponse<?> doRemoteTransactionRollback(RpcRollbackRequest req) throws RpcException {
        try {
            // 1.根据接口对应的 bean 名称获取回滚实现类
            String rollbackBeanName = rpcInvocationCoreFunc.lowercaseFirstLetter(req.getInterfaceName()) +
                    RPC_REMOTE_TRANSACTION_ROLLBACK_SUFFIX;
            Object bean = null;
            try {
                bean = applicationContext.getBean(rollbackBeanName);
            } catch (Exception ignored) {
            }
            if (bean == null) {
                throw RpcException.get(String.format("获取远程调用接口 %s 的远程事务回滚实现类 %s 失败, 请检查是否正确配置",
                        req.getInterfaceName(), rollbackBeanName));
            }

            // 2.获取要调用的方法
            Method method = null;
            try {
                method = bean.getClass().getMethod(req.getMethodName(), req.getParameterTypes());
            } catch (Exception ignored) {
            }
            if (method == null) {
                throw RpcException.get(String.format("获取远程调用接口 %s 的远程事务回滚方法 %s 失败, 请检查是否正确配置",
                        req.getInterfaceName(), req.getMethodName() + RPC_REMOTE_TRANSACTION_ROLLBACK_SUFFIX));
            }
            method.setAccessible(true);

            // 3.执行远程方法调用逻辑
            return RpcResponse.success(
                    // (1).通过反射调用对应的方法
                    method.invoke(bean, rpcInvocationCoreFunc.convertArgsToSpecificType(req.getArgs(), req.getParameterTypes())),
                    // (2).事务标识在回滚逻辑中无需关注, 因此直接默认赋值true即可
                    true);
        } catch (InvocationTargetException e) {
            throw RpcException.get(e.getTargetException().getMessage());
        } catch (Exception e) {
            throw RpcException.get(e.getMessage());
        }
    }

}
